package com.own.component.common.model;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.own.component.common.base.entity.BaseQuery;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * PageModel
 *
 * @author chenxueli
 * @date 2024-01-18 15:27:51
 */
@Getter
@Setter
@ToString
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class PageModel<T> implements Serializable {

    @Schema(title = "页码")
    private Integer page;

    @Schema(title = "行数")
    private Integer rows;

    @Schema(title = "总行数")
    private Integer total;

    @Schema(title = "数据列表")
    private List<T> list;

    @Schema(title = "是否已经到最后")
    private Boolean isLastPage;

    /**
     * 过滤条件
     */
    @JsonIgnore
    private List<Predicate<T>> predicates;

    /**
     * 处理器
     */
    @JsonIgnore
    private List<Consumer<T>> consumers;

    /**
     * 数据库查询数据构造方法
     *
     * @param list 数据类表
     */
    public PageModel(List<T> list) {
        this.list = list;
    }

    /**
     * 数据库查询数据构造方法
     *
     * @param pageInfo 分页数据
     */
    public PageModel(PageInfo<T> pageInfo) {
        this.page = pageInfo.getPageNum();
        this.rows = pageInfo.getPageSize();
        this.total = Long.valueOf(pageInfo.getTotal()).intValue();
        this.list = pageInfo.getList();
        this.isLastPage = pageInfo.isIsLastPage();
    }

    /**
     * 数据库查询数据构造方法
     *
     * @param list     数据类表
     * @param pageInfo 分页数据
     */
    public PageModel(List<T> list, PageInfo<?> pageInfo) {
        this(list);
        if (pageInfo != null) {
            this.page = pageInfo.getPageNum();
            this.rows = pageInfo.getPageSize();
            this.total = Long.valueOf(pageInfo.getTotal()).intValue();
            this.isLastPage = pageInfo.isIsLastPage();
        }
    }

    /**
     * mybatis分页插件自带方法
     *
     * @param list 数据信息
     * @param page 分页信息
     */
    public PageModel(List<T> list, Page<?> page) {
        this(list);
        if (page != null) {
            this.page = page.getPageNum();
            this.rows = page.getPageSize();
            this.total = Long.valueOf(page.getTotal()).intValue();
            checkIsLast();
        }
    }

    /**
     * IPage查询数据构造方法
     *
     * @param iPage 分页数据
     */
    public PageModel(IPage<T> iPage) {
        this.page = Integer.parseInt(iPage.getCurrent() + "");
        this.rows = Integer.parseInt(iPage.getSize() + "");
        this.total = Long.valueOf(iPage.getTotal()).intValue();
        this.list = iPage.getRecords();
        checkIsLast();
    }

    /**
     * 数据列表为空的情况
     *
     * @param query 查询对象
     */
    public PageModel(BaseQuery query) {
        this.page = query.getPage();
        this.rows = query.getRows();
        this.total = 0;
        this.list = new ArrayList<>();
        checkIsLast();
    }

    /**
     * 部分数据，模拟分页
     *
     * @param list  列表数据
     * @param page  页数
     * @param rows  每页数量
     * @param total 总数量
     * @author chenxueli
     * @date 2022-06-15 03:14:15
     */
    public PageModel(List<T> list, int page, int rows, int total) {
        this.page = page;
        this.rows = rows;
        this.total = total;
        this.list = list;
        checkIsLast();
    }

    /**
     * 部分数据，模拟分页
     *
     * @param list  列表数据
     * @param page  页数
     * @param rows  每页数量
     * @param total 总数量
     */
    public PageModel(T[] list, int page, int rows, int total) {
        this(
                new ArrayList<>(Arrays.asList(list)),
                page,
                rows,
                total
        );
    }

    /**
     * 部分数据，模拟分页
     *
     * @param list  列表数据
     * @param query 查询数据
     * @param total 总数量
     * @author chenxueli
     * @date 2022-06-15 03:14:15
     */
    public PageModel(List<T> list, BaseQuery query, int total) {
        this.page = query.getPage();
        this.rows = query.getRows();
        this.total = total;
        this.list = list;
        checkIsLast();
    }

    /**
     * 全数据，手动拆分
     *
     * @param list  数据列表
     * @param query 查询对象
     */
    public PageModel(List<T> list, BaseQuery query) {
        this.page = query.getPage();
        this.rows = query.getRows();
        this.total = list.size();
        var formIndex = (page - 1) * rows;
        var toIndex = page * rows;
        if (formIndex > total) {
            this.list = new ArrayList<>();
        } else if (toIndex > total) {
            this.list = list.subList(formIndex, total);
        } else {
            this.list = list.subList(formIndex, toIndex);
        }
        checkIsLast();
    }

    /**
     * 设置长度
     *
     * @param offset 偏移位置
     * @param rows   分页数量
     * @return 当前对象
     */
    public PageModel<T> offset(Integer offset, Integer rows) {
        if (offset % rows == 0) {
            this.page = offset / rows;
        } else {
            this.page = new BigDecimal(offset).divide(new BigDecimal(rows), 0, RoundingMode.CEILING).intValue();
        }
        this.isLastPage = offset + rows >= total;
        return this;
    }

    /**
     * 添加进另一个分页对象
     *
     * @param model 分页对象
     * @return 分页对象
     */
    public PageModel<T> put(PageModel<T> model) {
        this.total = model.getTotal();
        this.rows += model.getRows();
        this.list.addAll(model.getList());
        this.isLastPage = model.isLastPage;
        return this;
    }

    /**
     * 验证是否是最后了
     */
    private void checkIsLast() {
        this.isLastPage = ((long) this.page * this.rows) >= this.total;
    }

    /**
     * 转换数据对象信息
     *
     * @param function 转换方法
     * @param <TYPE2>  新的数据类型
     * @return 新的分页对象
     */
    public <TYPE2> PageModel<TYPE2> convert(Function<T, TYPE2> function) {
        var list = this.list.stream().map(function).collect(Collectors.toList());
        var pageModel = new PageModel<TYPE2>();
        pageModel.setPage(this.page);
        pageModel.setRows(this.rows);
        pageModel.setTotal(this.total);
        pageModel.setList(list);
        pageModel.setIsLastPage(this.isLastPage);
        return pageModel;
    }

    /**
     * 转换数据对象信息
     *
     * @param list 新列表
     * @return 新的分页对象
     */
    public <TYPE2> PageModel<TYPE2> replace(List<TYPE2> list) {
        var pageModel = new PageModel<TYPE2>();
        pageModel.setPage(this.page);
        pageModel.setRows(this.rows);
        pageModel.setTotal(this.total);
        pageModel.setList(list);
        pageModel.setIsLastPage(this.isLastPage);
        return pageModel;
    }

    /**
     * 过滤数据
     *
     * @param predicate 过滤条件
     * @return 当前对象
     */
    public PageModel<T> filter(Predicate<T> predicate) {
        if (predicates == null) {
            predicates = new ArrayList<>();
        }
        predicates.add(predicate);
        return this;
    }

    /**
     * 处理数据
     *
     * @param consumer 处理业务
     * @return 当前对象
     */
    public PageModel<T> peek(Consumer<T> consumer) {
        if (consumers == null) {
            consumers = new ArrayList<>();
        }
        consumers.add(consumer);
        return this;
    }

    /**
     * 集合数据
     *
     * @return 当前对象
     */
    public PageModel<T> collect() {
        if (consumers == null && predicates == null) {
            return this;
        }
        var stream = this.list.stream();
        if (predicates != null) {
            for (var predicate : predicates) {
                stream = stream.filter(predicate);
            }
        }
        if (consumers != null) {
            for (var consumer : consumers) {
                stream = stream.peek(consumer);
            }
        }
        this.list = stream.collect(Collectors.toList());
        return this;
    }

    /**
     * 合并数据
     *
     * @param model 分页对象
     * @return 当前对象
     */
    public PageModel<T> concat(PageModel<T> model) {
        this.list.addAll(model.getList());
        this.total += model.getTotal();
        this.isLastPage = false;
        return this;
    }

    /**
     * 是否为空
     *
     * @return 是否为空
     */
    public boolean isEmpty() {
        return this.list == null || this.list.isEmpty();
    }

}
